#include<stdio.h>
#include<ctype.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<assert.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>
#define NUM 1024
#define COM_NUM 64
#define NONE_REDIR 0
#define INPUT_REDIR 1
#define OUPUT_REDIR 2
#define APPEND_REDIR  4
char lineCommand[NUM];
char *myargv[COM_NUM];
int exit_code=0;
int exit_sign=0;
int redirType = NONE_REDIR;
char* myFile = NULL;

#define trimSpace(start) do{while(isspace(*start)) ++start;}while(0)


void commandCheck(char* commands)
{
    assert(commands);
    char *start = commands;
    char *end = commands+strlen(commands);

    while(start<end)
    {
        if(*start == '>')
        {
            *start = '\0';
            start++;
            if(*start == '>')
            {
                start++;
                redirType = APPEND_REDIR;
            }
            else 
            {
                
                redirType = OUPUT_REDIR;
            }

            trimSpace(start);
            myFile = start;
            break;
        }
        else if(*start == '<')
        {
            *start = '\0';
            start++;
            redirType = INPUT_REDIR;
            trimSpace(start);
            myFile = start;
            break;
        }
        else 
            start++;
    }
}

//最新添加重定向功能!!!!!
int main()
{
    while(1)
    {
        redirType = NONE_REDIR;
        myFile = NULL;

        printf("[wml @ my_bash path#]");
        fflush(stdout);
        
        //获取输入行内容
        char *s = fgets(lineCommand,sizeof(lineCommand)-1,stdin);
        assert(s != NULL);
        (void)s;

        lineCommand[strlen(lineCommand)-1] = 0;

        //重定向:
        //"ls -a -l > "test.txt""  ---->  "ls -a -l"  >  "test.txt"
        //"ls -a -l >> "test.txt""  ---->  "ls -a -l"  >>  "test.txt"
        //"cat < "test.txt""  ---->  "cat"  <  "test.txt"
    
        commandCheck(lineCommand);

        //切割字符串
        myargv[0] = strtok(lineCommand," ");
        int i = 1;

        //添加颜色选项
        if(myargv[0]!= NULL && strcmp(myargv[0],"ls") == 0  )
        {
            myargv[i++]  = (char*) "--color=auto";
        }

        //读取每个选项
        while(myargv[i++] = strtok(NULL," "));
        
        //解决工作路径无法改变的问题
        if(myargv[0]!=NULL && strcmp(myargv[0],"cd") == 0)
        {
            if(myargv[1]!=NULL) 
                chdir(myargv[1]);
            continue;
        }

        if(myargv[0]!=NULL && myargv[1]!=NULL && strcmp(myargv[0],"echo")==0 )
        {
            if(strcmp(myargv[1],"$?")==0)
                printf("exit_code-->%d | exit_sign-->%d\n",exit_code,exit_sign);
            else 
                printf("%s\n",myargv[1]);
            continue;
        }

#ifdef DEBUG 
        for(int i=0;myargv[i];i++)
            printf("myargv[%d]:%s\n",i,myargv[i]);
#endif

        pid_t id = fork();
        assert(id!=-1);

        if(id==0)
        {
            switch(redirType)
            {
                case NONE_REDIR:
                    break;
                case INPUT_REDIR:
                {
                    int fd  = open(myFile,O_RDONLY);
                    if(fd<0) {perror("open");return 1;}
                    dup2(fd,0);
                }
                     break;
                case OUPUT_REDIR:
                case APPEND_REDIR:
                {
                    umask(0);
                    int flag = O_WRONLY | O_CREAT;
                    if(redirType == APPEND_REDIR) flag |= O_APPEND;
                    else flag |= O_TRUNC;

                    int fd  = open(myFile,flag,0666);
                    if(fd<0){perror("open");return 2;};
                    dup2(fd,1);
                }
                    break;
                default:
                    printf("bug!\n");
                    break;

            }
            execvp(myargv[0],myargv);
           _exit(1);
        }

        int status=0;
        pid_t ret = waitpid(id,&status,0);
        assert(ret!=-1);
        (void)ret;

        exit_sign = (status & 0x7f);
        exit_code = (status>>8) & 0xff;


    }
    return 0;
}
